#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# Copyright 2022 Huaqin Technology. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#    * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#    * Neither the name of Huaqin Technology nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import sys
import os
import re
import itertools

import configparser
import logging
import logging.config

from tws_lint_err_code import ErrorDef, ErrorsDict, LINE_LENGTH_MAX, HEADER_FILE_INCLUDE_FILTER

#print("===>tws_lint_v03.py: ", __name__)   # note.
logger = logging.getLogger(__name__)

# & 'C:\Program Files\Python37\python.exe' -m pydoc -w .\tws_c_codestyle_v0.3.py
_USAGE = """
Synatax: python3 tws_lint_v0.3.py <configfile_path> <file> [files]
"""


_valid_extentions_re_pattern = r'[ch]'

_CHECK_ITEM_FILENAME_FORMAT = "CHECK_FILENAME_FORMAT"
_CHECK_ITEM_NEWLINE_END_OF_FILE = "CHECK_NEW_LINE_END_OF_FILE"
_CHECN_ITEM_LINE_LENGTH = "CHECK_LINE_LENGTH"
_CHECK_ITEM_LINE_END_OF_BLANK = "CHECK_LINE_END_OF_BLANK"
_CHECK_ITEM_ILLEGAL_TAB = "CHECK_ILLEGAL_TAB"
_CHECK_ITEM_ILLEGAL_CHARACTER = "CHECK_ILLEGAL_CHARACTER"
_CHECK_ITEM_SECURE_FUNC = "CHECK_SECURE_FUNC"


_CHECK_ITEM_SUPPORTED = (_CHECK_ITEM_SECURE_FUNC,)
_CHECK_ITEM_NEED = list()


def _PrintUsage(message):
    """Print a brief usage string and exits, optionally with an error message.

    Args:
        message: The optional error message.
    """
    print(_USAGE)
    # print('The valid file extentions for file name is:')
    # print(_valid_extentions)

    if message:
        sys.exit('\nFatal _Error: ' + message)
    else:
        sys.exit(1)

_CONFIG_INI_SECTION_ROOT = 'root'
_CONFIG_INI_SECTION_KEY_VALUE_ITEM = 'special_checklint_item'
def _parse_twslint_config(configfile):
    # check_item_list = list()
    global _CHECK_ITEM_NEED
    if not os.path.exists(configfile):
        logger.info(f"configgile:{configfile} not exist!!!")
        return []
    config = configparser.ConfigParser()
    config.read(configfile)

    for item in _CHECK_ITEM_SUPPORTED:
        if config.has_option(_CONFIG_INI_SECTION_ROOT, _CONFIG_INI_SECTION_KEY_VALUE_ITEM):
            values_list = [element.strip() for element in config.get(_CONFIG_INI_SECTION_ROOT,_CONFIG_INI_SECTION_KEY_VALUE_ITEM).split(',')]
            logger.info(f"{_CONFIG_INI_SECTION_KEY_VALUE_ITEM}:{values_list}")
            if item in values_list:
                _CHECK_ITEM_NEED.append(item)
    return _CHECK_ITEM_NEED

class TwsLint(object):
    VALID_EXTENTIONS = ("c", "h") # 支持的文件名后缀
    LINE_COUNT_MIN = 3 # 解析文件的最小行数，小于等于这个行数，会认为文件是空文件
    LINE_LENGTH_MAX = LINE_LENGTH_MAX

    def __init__(self, configs, filepath) -> None:
        self.filepath = filepath # 当前需要解析文件的路径
        self.lint_configs = configs # 解析的配置
        self.file_extention = None # 当前解析文件名的后缀，例如.c, .h等
        self.lines = None # list类型，文件中的所有行
        self.lines_without_single_line_comments = list() # 基于self.line，将所有的单行注释替换为空白
        self.lines_without_all_comments = list() # 基于self.lines_without_single_line_comments, 将所有注释替换为空白
        self.lines_without_all_comments_and_hash_if = list() # 基于self.lines_without_all_comments, 去掉#if相关的结构
        self.lines_without_all_comments_and_hash_if_and_hash_define = list() # 基于self.lines_without_all_comments_and_hash_if, 去掉#define相关结构
        self.lines_without_all_comments_and_hash_if_and_hash_define_and_string = list() # 基于self.lines_without_all_comments_and_hash_if_and_hash_define, 去掉所有的字符串
        self.lines_without_all_comments_and_hash_if_and_hash_define_and_string_and_constructs = list() # 基于self.lines_without_all_comments_and_hash_if_and_hash_define_and_string, 去掉所有的constructs
        self.LINES_COUNT_RANGE_START = None # 给range方法使用，表示lines的实际起始行，第1行，第0行为marker
        self.LINES_COUNT_RANGE_STOP = None # 给range方法使用，表示lines的实际结束行，倒数第2行，最后一行为marker
        self.LINES_COUNT_TRUE_COUNT = None # lines的真实总行数
        self.LINES_COUNT_WITH_MARKER = None # lines加上前、后marker的总行数
        self.LINES_ITERATOR = None # range(self.LINES_COUNT_RANGE_START, self.LINES_COUNT_RANGE_STOP), 迭代所有的行数
        self.supperss_info_dict = dict() # {"suppress_code": [line_num, line_num, ...]}, {"504": [22, 23, 25, 27]}
        self.golbal_suppress_list_from_config = list() # 全局suppress code list, 由全局配置生成
        self.golbal_suppress_list_default = list() # 全局定义的suppress code list,
        self.output_buff_list = list() # 存放此文件中所有输出的错误信息

        """XXX_CONSTRUCT_INFO
            enum, function, struct, union等定义的结构信息
            type: list[{dict}, {dict}, {dict}]
            {
                'line_start':     int   # The start line num of the construct, sometimes before the brackets start line.
                'brackets_start': int   # The start line num of the brackets.
                'line_stop':      int   # The end line num of the construct.
                'depth':          int   # The max depth of the construct, represent how many '{}' it has.
                'data':           list  # The data in line of the whole construct.
            }
        """
        self.construct_info_function_lable = "function"
        self.construct_info_function_list = list() # function definition info

        self.construct_info_enum_label = "enum"
        self.construct_info_enum_list = list() # enum definition info

        self.construct_info_struct_label = "struct"
        self.construct_info_struct_list = list() # struct definition info

        self.construct_info_union_label = "union"
        self.construct_info_union_list = list() # union definition info

        self.construct_info_hash_if_label = "#if"
        self.construct_info_hash_if_list = list() # #if/#elif/#else/#endif info

        self.construct_info_hash_define_label = "#define"
        self.construct_info_hash_define_list = list() # '#define' line info

        self.construct_info_include_label = "#include"
        self.construct_info_include_list = list() # #include info

        self.construct_info_variable_define_label = "array[]="
        self.construct_info_variable_define_list = list() # 变量定义, 普通变量, 结构体变量, 数组变量

        self.construct_info_function_statement_label = "function_statement"
        self.construct_info_function_statement_list = list() # 函数声明，非定义

    def _output_error(self, error_code: int, line_num: int, line_info: str) -> bool:
        # 默认支持的code ===> 默认全局抑制的code ===> 由外部配置传进来的全局抑制的code ===> 由文件解析mark逐行的抑制code
        err_code = str(error_code)
        err_line_num = line_num
        err_line_info = line_info
        error_def = ErrorsDict.get(err_code)

        if not error_def:
            logger.error("_output_error failed: Unsupported error code: [%s] [%d] [%s] [%s]", err_code, err_line_num, err_line_info, self.filepath)
            return False

        if err_code in self.golbal_suppress_list_default:
            logger.info("_output_error: Error code suppressed by default: [%s] [%d] [%s] [%s]", err_code, err_line_num, err_line_info, self.filepath)
            return True

        if err_code in self.golbal_suppress_list_from_config:
            logger.info("_output_error: Error code suppressed by configfile: [%s] [%d] [%s] [%s]", err_code, err_line_num, err_line_info, self.filepath)
            return True

        suppressed_lines = self.supperss_info_dict.get(err_code)
        if suppressed_lines:
            if err_line_num in suppressed_lines:
                logger.info("_output_error: Error code suppressed by maker in checking file: [%s] [%d] [%s] [%s]", err_code, err_line_num, err_line_info, self.filepath)
                return True

        output_str = f"[{self.filepath}]    [lint_errshow]:[line:{line_num:>6}]    [err_code:{err_code:>5}]    [err_msg:{error_def.prompt_msg:<45}]    [description:{error_def.description}]    [line_info:{err_line_info}]"

        self.output_buff_list.append(output_str)


    def _count_space_on_the_left_side(self, line: str) -> int:
        """计算字符串左侧的空格数量, 并返回空格数量
        只计算左侧字符串, 用于比较两行的缩进是否符合规范.

        Args:
            line: 需要计算左侧空格数量的字符串.

        Returns:
            字符串左侧的空格数量.
        """
        return len(line) - len(line.lstrip())


    def _process_file_to_lines(self) -> bool:
        filepath = self.filepath
        file_extention = filepath[filepath.rfind(".") + 1]
        if file_extention not in self.VALID_EXTENTIONS:
            logger.error("Unsupported file extention: %s, valid extention: " + ", ".join(["%s"] * len(self.VALID_EXTENTIONS)), filepath, self.VALID_EXTENTIONS)
            return False
        self.file_extention = file_extention

        try:
            lines = open(filepath, mode="r", encoding="utf8").read().split("\n")
        except:
            logger.error("Could not open file: %s", filepath)
            return False

        if len(lines) <= self.LINE_COUNT_MIN:
            logger.info("File is empty, no need to check: %s", filepath)
            return False

        lines = (['// marker so line numbers and indices both start at 1'] + lines + ['// marker so line numbers end in a known way'])
        self.lines = lines
        self.LINES_COUNT_RANGE_START = 1
        self.LINES_COUNT_RANGE_STOP = len(self.lines) - 1
        self.LINES_COUNT_TRUE_COUNT = len(self.lines) - 2
        self.LINES_COUNT_WITH_MARKER = len(self.lines)

        self.LINES_ITERATOR = range(self.LINES_COUNT_RANGE_START, self.LINES_COUNT_RANGE_STOP)

        return True


    def _process_twslint_mark(self) -> bool:
        """_summary_
        参考: https://blog.csdn.net/yuelai_217/article/details/122923451
        * 只能使用/* */形式的注释
        * 左侧"/*"与"twslint"字符间有且仅有一个空格
        * 右侧"*/" 与错误号之间, 有且仅有一个空格
        * 屏蔽多个错误时, 用", "英文逗号加一个空格, 不能有多个空格
        * 同一行中, "+" "-" "!"不能混用

        1、格式一: 多行
        -e#  禁止指定的错误消息，#代表数字或是数字匹配符，错误消息的编号为#。
        +e#  恢复指定的错误消息，错误消息的编号为#。
        a. /* twslint -126 */           用于新行, 从此行开始屏蔽126的错误
        b. /* twslint +126 */           用于新行, 从此行开始恢复126的错误

        c. /* twslint -126, -127 */     用于新行, 从此行开始屏蔽126的错误
        d. /* twslint +126, +127 */     用于新行, 从此行开始恢复126的错误

        e. /* twslint -file */          用于文件首行, 标识整个文件不进行twslint检查

        ---不使用f. /* twslint -all */           用于新行, 从此行开始, 屏蔽所有的错误
        ---不使用g. /* twslint -restore */       用于新行, 从此行开始，恢复所有的错误

        6、格式二: 单行
        a. /* twslint !126 */           用于新行, 屏蔽下一行的126错误
        b. /* twslint !126, !127 */     同上，用于新行, 屏蔽下一行的多个错误

        Returns:
            bool: 是否需要对文件进行检查, False表示不需要对文件进行检查
        """
        # RE_PATTERN_COMPILED = re.compile(r"^/\* twslint (?:([\+\-\!])(\d+))(?:, ([\+\-\!])(\d+))* \*/$")
        RE_PATTERN_COMPILED = re.compile(r"^/\* twslint ([\+\-\!]\d+(?:, [\+\-\!]\d+)*) \*/$")
        RE_PATTERN_COMPILED2 = re.compile(r"([\+\-\!])(\d+)")
        lines = self.lines
        suppress_code_list = list()
        suppress_info_dict = dict()
        if lines[1] == "/* twslint -file */":
            logger.info("File exist '/* twslint -file */', no need do twslint.")
            return False

        for line_num in self.LINES_ITERATOR:
            # 对于已设置的suppress code，将当前行加入到suppress info中
            for code in suppress_code_list:
                if not suppress_info_dict.get(code):
                    suppress_info_dict[code] = list()
                suppress_info_dict.get(code).append(line_num)

            line_striped = lines[line_num].strip()
            if not line_striped:
                continue
            matches = RE_PATTERN_COMPILED.findall(line_striped)
            if not len(matches):
                continue
            matches = RE_PATTERN_COMPILED2.findall(matches[0])
            if not len(matches):
                continue
            matched_pattern = list(itertools.chain(*matches))
            # matched_pattern = matches[0]
            suppress_type = matched_pattern[0]
            for stype in matched_pattern[::2]:
                if stype and (suppress_type != stype):
                    # logger.error("Unsupported twslint string: [%s]", line_striped)
                    self._output_error(101, line_num, line_striped)
                    return False

            for suppress_code in matched_pattern[1::2]:
                if not suppress_code:
                    continue

                # line_num循环开始时，会check所有当前使能的suppres code，并将当前line num加入到suppress info中
                if suppress_type == "-":
                    if suppress_code not in suppress_code_list:
                        suppress_code_list.append(suppress_code)
                elif suppress_type == "+":
                    if suppress_code in suppress_code_list:
                        suppress_code_list.remove(suppress_code)
                    if not suppress_info_dict.get(suppress_code):
                        continue
                    if line_num in suppress_info_dict.get(suppress_code):
                        suppress_info_dict.get(suppress_code).remove(line_num) # suppress info 不包含twslint设置行
                elif suppress_type == "!":
                    if not suppress_info_dict.get(suppress_code):
                        suppress_info_dict[suppress_code] = list()
                    suppress_info_dict.get(suppress_code).append(line_num + 1)
                else:
                    # logger.error("Unsupported twslint suppress type: [%s] in [%s]", suppress_type, line_striped)
                    self._output_error(102, line_num, line_striped)
                    return False

        self.supperss_info_dict = suppress_info_dict
        return True


    def _get_filename_without_path(self, filename):
        """去掉文件名中的路径, 并返回完整的文件名.

        Args:
            filename: 需要处理的文件名(包含完整路径)

        Returns:
            不带路径的文件名.
        """
        name = re.sub(r'\\', '/', filename) # 将反斜杠'\' 先替换为'/', 便于split处理.
        name = re.split(r'/', name)[-1] # 使用'/'分割字符串, 并取出最后一个元素（文件名）.
        if not name:
            _PrintUsage('filename error' + filename)

        return name


    def _check_filename_format(self):
        """检查文件命名规范.
        1. 名字全部使用英文小写字母a-z, 中间可以有下划线'_'.
        2. 除了文件类型后缀'.c''.h', 文件名中不能有其他的'.'符号.
        3. 不能使用'.'或'_开头', 只能使用英文字母开头.

        Errors:
            category: [whitespace/filename]
            confidence: [5]
            message: [Filename format error: "xxx_xxx.h"]

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        RE_PATTERN_COMPILED = re.compile(r'^[a-z][a-z_0-9]*[a-z0-9].' + _valid_extentions_re_pattern + r'$')
        if not RE_PATTERN_COMPILED.match(self._get_filename_without_path(self.filepath)):
            self._output_error(120, 0, self._get_filename_without_path(self.filepath))


    def _check_file_end_of_newline(self):
        """检查文件最后一行是否为空行.
        1. 文件最后一行, 应为空行.
            Errors:
                category: [whitespace/eof_newline]
                confidence: [5]
                message: [Need new-line at the end of file]
        2. 文件倒数第二行, 应有代码.
            Errors:
                category: [whitespace/eof_newline]
                confidence: [5]
                message: [Only 1 blank line at the end of the file.]
        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        lines = self.lines
        if lines[-2].strip():
            self._output_error(121, self.LINES_COUNT_TRUE_COUNT, lines[-2].strip())
        elif not lines[-3].strip():
            self._output_error(122, self.LINES_COUNT_TRUE_COUNT - 1, lines[-3].strip())


    def _check_line_length(self):
        """检查每行字符长度
        1. 包含前后空白字符.
        2. 最大字符数量由"_MAX_LINE_LENS"定义.

        Errors:
            category: [whitespace/line_length]
            confidence: [5]
            message: [Lines should be <= %i characters long, but you have %i]

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        lines = self.lines
        for line_num in self.LINES_ITERATOR:
            if len(lines[line_num]) > self.LINE_LENGTH_MAX:
                self._output_error(123, line_num, lines[line_num])


    def _check_line_end_with_blank(self):
        """检查行尾无用空白字符
        1. 检查行尾是否有空白(空格, TAB, 软换行等)
        TODO: 2. 将行尾的空白字符去掉drop, 便于后续规范检查, 减少重复报错.

        Errors:
            category: [whitespace/unused_space]
            confidence: [5]
            message: [Please remove unused space or tab at end of the line]

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        lines = self.lines
        RE_PATTERN_COMPILED = re.compile(r'^.*\s+$')
        for line_num in self.LINES_ITERATOR:
            if RE_PATTERN_COMPILED.match(lines[line_num]):
                self._output_error(124, line_num, lines[line_num])


    def _check_file_with_illegal_tab(self):
        """检查否有非法符号
        1. 文件中不能包含'\\t', '\\f', '\\r'等字符.

        Errors:
            category: [whitespace/illegal_tab]
            confidence: [5]
            message: [Please remove illegal symbols: "\\t", "\\f", "\\r".]

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        lines = self.lines
        RE_PATTERN_COMPILED = re.compile(r'\r|\t|\f')
        for line_num in self.LINES_ITERATOR:
            if RE_PATTERN_COMPILED.search(lines[line_num]):
                self._output_error(125, line_num, lines[line_num])


    def _check_file_language(self):
        """检查是否有中文字符
        1. 文件中不能包含中文字符.

        Errors:
            category: [whitespace/language]
            confidence: [5]
            message: [Cannot contain Chinese characters.]

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        lines = self.lines
        RE_PATTERN_COMPILED = re.compile(r'[\u4e00-\u9fa5]')
        for line_num in self.LINES_ITERATOR:
                if RE_PATTERN_COMPILED.search(lines[line_num]):
                    self._output_error(126, line_num, lines[line_num])


    def _check_include_rules_in_header_file(self):
        """检查头文件的文件引用.
        1. 头文件中, 不应该包含其他头文件(不能有'#include'符号).

        Errors:
            category: [whitespace/header_file]
            confidence: [5]
            message: [Header file(xxx.h) cannot include headerfiles.]

        Args:
            filepath: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        file_extention = self.file_extention
        lines = self.lines
        filepath = self.filepath
        if file_extention != 'h':
            return

        _INCLUDE_PATTERN_COMPILED = re.compile(r'^\s*#include')
        _INCLUDE_FIND_FILENAME_PATTERN_COMPILED = re.compile(r"^\s*#include\s+[\"<]\s*([a-zA-Z0-9_/]+.(?:h|txt))\s*[\">]\s*$")
        include_filter_list = HEADER_FILE_INCLUDE_FILTER

        for line_num in self.LINES_ITERATOR:
            line = lines[line_num]
            if _INCLUDE_PATTERN_COMPILED.match(lines[line_num]):
                header_filename = _INCLUDE_FIND_FILENAME_PATTERN_COMPILED.findall(line)
                if header_filename and len(header_filename) == 1:
                    header_filename = header_filename[0].strip()
                    if header_filename in include_filter_list:
                        continue
                self._output_error(127, line_num, lines[line_num])


    def _check_header_file_protect_by_marco(self):
        """检查头文件的宏保护.
        1. 使用与文件名同名的宏, 如头文件aaa_bbb.h, 应使用__AAA_BBB_H__来保护.
        2. 前后需使用双下划线"__"
        example:
            filename: aaa_bbb.h
            #ifndef __XXX_XXX_H__ // 必须在第一行.
            #define __XXX_XXX_H__ // 必须在第二行.
            ///code
            #endif // __XXX_XXX_H__ // 必须在倒数第一行.

        Errors:
            category: [whitespace/header_file]
            confidence: [5]
            message: [Header file(xxx.h) need to be protected correctly.]

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        file_extention = self.file_extention
        filepath = self.filepath
        lines = self.lines
        if file_extention != 'h':
            return
        marco = "__" + re.sub(r'\.', '_', self._get_filename_without_path(filepath).upper()) + "__"
        _POUND_IFNDEF_PATTERN = r"^\s*#ifndef "
        _POUND_IFNDEF_PATTERN_COMPILED = re.compile(_POUND_IFNDEF_PATTERN)
        for line_num in self.LINES_ITERATOR:
            line = lines[line_num]
            line_next = lines[line_num + 1]
            if _POUND_IFNDEF_PATTERN_COMPILED.match(line):
                if (line != '#ifndef ' + marco):
                    self._output_error(128, line_num, line)
                if (line_next != '#define ' + marco):
                    self._output_error(129, line_num + 1, line_next)
                if (lines[-3] != '#endif // ' + marco):
                    self._output_error(130, self.LINES_COUNT_TRUE_COUNT - 1, lines[-3])
                break

    def _check_file_illegal_extern(self):
        """禁止在'.c'文件中使用'extern'.
        1. '.c'文件中, 不能有extern开头的行.
        TODO: '.h'文件中的extern需要限制?

        Errors:
            category: [whitespace/c_file]
            confidence: [5]
            message: [Src file(xxx.c) forbid to use "extern".]

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        file_extention = self.file_extention
        lines = self.lines
        # if file_extention != 'c':
        #     return

        _EXTERN_PATTERN = re.compile(r'^\s*extern')
        for line_num in self.LINES_ITERATOR:
            if _EXTERN_PATTERN.match(lines[line_num]):
                self._output_error(131, line_num, lines[line_num])


    def _check_single_line_comments_and_replace_by_blank(self):
        """检查单行注释('//')规范
        单行注释, 分为新行模式 和 代码行模式:
        1. 新行模式: 整个注释位于一个独立的新行, 前面没有代码.
        2. 代码行模式: 注释位于代码最后.
        3. 公共规则:
            a. "//"符号与注释间, 应有且只有一个空格: "// comments"
            b. 禁止注释内容为空的无效注释:
                "//////  "
                "//   "
            c. 不能同时有多于两个的斜杠:'///'
        4. 新行模式规则:
            a. 当"//"位于新行时, 应位于代码上方一行, 无空行:
                "// comments"
                "code;"
            b. 当"//"位于新行时, 缩进应保持与代码一致(在缩进中检查)
                "    // comments"
                "    code;"
        5. 代码行模式规则:
            a. 当"//"位于代码行尾时,应与代码间至少有1个空格: "code; // comments"

        Note: 在规范检查过程中, 会将这些注释替换为空, 不影响行数, 也不修改原文件.

        Errors: 单行模式: '//'和注释间, 没有空格, 或有多个空格.
            category: [whitespace/sigle_line_comment]
            confidence: [5]
            message: [(Newline mode) Format error, syntax: "// xxx".]

        Errors: 单行模式: 注释不应该在文件的最后一行.
            category: [whitespace/sigle_line_comment]
            confidence: [5]
            message: [(Newline mode) Should not be the last line.]

        Errors: 单行模式: 注释的下一行不应该为空.
            category: [whitespace/sigle_line_comment]
            confidence: [5]
            message: [(Newline mode) Should not be blank in next line.]

        Errors: 单行模式: 注释的缩进, 应和下一行相等.
            category: [whitespace/sigle_line_comment]
            confidence: [5]
            message: [(Newline mode) Indentation error, should be same with next line.]

        Errors: 多行模式: '//'前和后, 有且只有一个空格.
            category: [whitespace/sigle_line_comment]
            confidence: [5]
            message: [(Code-line mode) format error. syntax: "code // comments".]

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        lines = self.lines.copy()
        NEWLINE_MODE_PATTERN_COMPILED = re.compile(r"^\s*///*")
        NEWLINE_MODE_RULE_PATTERN_COMPILED = re.compile(r"^\s*// \S.*$")
        CODE_LINE_MODE_PATTERN_COMPILED = re.compile(r"^\s*[^ \t\r\n\f/].*///*")
        CODE_LINE_MODE_RULE_PATTERN_COMPILED = re.compile(r"\S // \S.*$")
        IS_NEXT_LINE_BRACKETS_COMPILED = re.compile(r"^\s*}.*$")

        for line_num in self.LINES_ITERATOR:
            line = lines[line_num]
            line_next = lines[line_num + 1]
            if NEWLINE_MODE_PATTERN_COMPILED.match(line): # 检查是否单行注释的新行模式
                if not NEWLINE_MODE_RULE_PATTERN_COMPILED.match(line): # 检查注释规范是否正确.
                    self._output_error(200, line_num, line)
                if line_num == self.LINES_COUNT_TRUE_COUNT: # 注释不应该为最后一行
                    self._output_error(201, line_num, line)
                if not line_next.strip(): # 注释的下一行, 应该有代码
                    self._output_error(202, line_num, line)
                if self._count_space_on_the_left_side(line) != self._count_space_on_the_left_side(line_next): # 检查缩进是否与下一行相等
                    # 下一行是否为"}", 若是, 则应有4个空格的缩进
                    if not (IS_NEXT_LINE_BRACKETS_COMPILED.match(line_next) and (self._count_space_on_the_left_side(line) == self._count_space_on_the_left_side(line_next) + 4)):
                        self._output_error(203, line_num, line)
                # replace this lines as blank
                lines[line_num] = ''

            if CODE_LINE_MODE_PATTERN_COMPILED.match(line):
                if not CODE_LINE_MODE_RULE_PATTERN_COMPILED.search(line):
                    self._output_error(204, line_num, line)
                # replace this comments as blank
                # print(line_num, lines[line_num])
                lines[line_num] = re.sub(r'//.*$', '', line)
                # print(line_num, lines[line_num])

        self.lines_without_single_line_comments = lines.copy()


    def _check_multi_line_comments_and_replace_by_blank(self):
        """检查多行注释规范"/* */":
        多行注释, 分为 '单行模式', '代码单行模式', '多行模式'.
        1. 单行模式: 整个注释位于新行, 前后无代码.
        2. 代码单行模式: 注释位于代码行行尾或中间.
        3. 多行模式: 整个注释包含2行或以上.
        example:
        /**
        * comments
        * comments
        *
        */

        1. 单行模式规则:
            a. 注释内容, 与注释符号之间, 应有且仅有一个空格:/* xxx */
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Single-line mode) Format error syntax: "   /* xxx */".]
            b. 注释不应为最后一行.
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Single-line mode) Should not be the last line.']
            c. 当下一行不为空, 且下一行有'}'符号时,  缩进应比下一行多4个空格
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Single-line mode) Indentation error, next line is '}', 4 more space in indentation.]
            d. 当下一行不为空, 且下一行没有'}'符号时, 缩进应与下一行一致。
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Single-line mode) Indentation error, indentation should be same with next line.]
            e. 当下一行为空, 且上一行不为空时, 缩进应与上一行一致。
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Single-line mode) Indentation error, indentation should be same with previous line.]
            f. 当下一行为空, 且上一行为空时, 此注释不应该存在, 应该删除。
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Single-line mode) Indentation error, should not exist independently, please delete it.]

        2. 单行代码模式规则:
            a. 注释内容与注释符之间, 有且只有一个空格: "/* comments */"
            b. 注释应位于行末, 不应夹在代码之间: "code /* comments */ code;"
            c. 注释内容与代码之间, 有且只有一个空格: "code; /* comments */"
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Code-line mode) Syntax error: "code /* comments */"]
        3. 多行模式规则:
            a. 起始行应使用新行, 前后不能有代码, 起始行使用符号"/**".
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Multi-line mode) Start-line syntax error: "newline /**$".]
            b. 起始行的缩进, 应比下一行少一个空格: " *" 比 "/**"多一个空格.
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Multi-line mode) Start-line indentation error.]
            c. 中间行使用符号" * comments" 或 " *", 注意'*'前的空格.
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Multi-line mode) Mid-line syntax error: " * comments$".]
            d. 中间行缩进, 应和下一行一致.
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Multi-line mode) Mid-line indentation error.]
            e. 结束行应使用新行, 前后不能有代码, 使用符号" */",  注意空格.
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Multi-line mode) Stop-line syntax error: " */$'.]
            f. 结束行, 当下一行不为空时, 缩进应比下一行多一个空格: " */"前面有一个空格.
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Multi-line mode) Stop-line indentation error. Next line is not None.]
            g. 结束行, 当下一行为空时, 缩进应为1个空格: " */"前面有一个空格.
                Errors:
                category: [whitespace/multi_line_comment]
                confidence: [5]
                message: [(Multi-line mode) Stop-line indentation error. Next line is None.]

        Note: 在规范检查过程中, 会将这些注释替换为空, 不影响行数, 也不修改原文件.

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        SINGLE_LINE_MODE_PATTERN = re.compile(r'^\s*/\*.*\*/\s*$') # "newline /* comments */"
        SINGLE_LINE_MODE_RULE_PATTERN = re.compile(r'^\s*/\* \S+.*\S+ \*/$')
        CODE_LINE_MODE_PATTERN = re.compile(r'\S.*/\*.*\*/') # "code /* comments */"
        CODE_LINE_MODE_RULE_PATTERN = re.compile(r'\S /\* \S.*\S \*/$')
        MULIT_LINE_MODE_START_PATTERN = re.compile(r'/\*+') # "/**"
        MULIT_LINE_MODE_START_RULE_PATTERN = re.compile(r'^\s*/\**$')
        MULIT_LINE_MODE_MID_RULE_PATTERN = re.compile(r'^\s* \*(.*\S)?$')
        MULIT_LINE_MODE_STOP_PATTERN = re.compile(r'\*/') # " */"
        MULIT_LINE_MODE_STOP_RULE_PATTERN = re.compile(r'^\s* \*/$')

        lines = self.lines_without_single_line_comments.copy()

        for line_num in self.LINES_ITERATOR:
            line = lines[line_num]
            if SINGLE_LINE_MODE_PATTERN.match(line): # 是否为单行模式
                if not SINGLE_LINE_MODE_RULE_PATTERN.match(line): # 单行模式是否规范
                    self._output_error(220, line_num, line)
                if line_num == self.LINES_COUNT_TRUE_COUNT: # 注释不应该为最后一行
                    self._output_error(221, line_num, line)
                # if not lines[line_num + 1].strip(): # 注释的下一行, 应该有代码 # 对于需要start 和 end的, 此处无法检查, 取消.
                #   _Error(filename, line_num, 'whitespace/multi_line_comment', 5,
                #     '(Single-line mode) Should not be blank in next line.')
                # if (_CountLeftSpace(lines[line_num]) != _CountLeftSpace(lines[line_num + 1])) and (not lines[line_num + 1].strip()): # 检查缩进是否与下一行相等 # 当下一行部位空时, 才检查缩进
                #   # 下一行是否为"}", 若是, 则应有4个空格的缩进
                #   if not (re.match(r'^\s*}.*$', lines[line_num + 1]) and (_CountLeftSpace(lines[line_num]) == _CountLeftSpace(lines[line_num + 1]) + 4)):
                #     _Error(filename, line_num, 'whitespace/multi_line_comment', 5,
                #       '(Single-line mode) Indentation error, should be same with next line.')

                # 开始检查缩进
                line_next = lines[line_num + 1]
                line_next_striped = line_next.strip()
                if line_next_striped: # 当下一行不为空时
                    if re.match(r'^\s*}.*$', line_next): # 如果下一行有'}', 则需要增加4个空格的缩进
                        if (self._count_space_on_the_left_side(line) != (self._count_space_on_the_left_side(line_next) + 4)):
                            self._output_error(222, line_num, line)
                    else: # 下一行没有'}'时, 缩进应与下一行一致
                        if self._count_space_on_the_left_side(line) != self._count_space_on_the_left_side(line_next):
                            self._output_error(223, line_num, line)
                else: # 当下一行为空时
                    line_pre = lines[line_num - 1]
                    line_pre_striped = line_pre.strip()
                    if line_pre_striped: # 如果上一行不为空, 缩进应与上一行一致。
                        if self._count_space_on_the_left_side(line) != self._count_space_on_the_left_side(line_pre):
                            self._output_error(224, line_num, line)
                    else: # 如果上一行也为空, 应删除此注释
                        self._output_error(225, line_num, line)

                lines[line_num] = ''

        # 把单行模式全部替代空格后, 重新开始匹配, 避免注释影响.
        for line_num in self.LINES_ITERATOR:
            line = lines[line_num]
            if CODE_LINE_MODE_PATTERN.search(line): # 代码行的单行模式,  缩进随代码行本身, 不检查此行缩进
                if not CODE_LINE_MODE_RULE_PATTERN.search(line): # 注释是否规范
                    self._output_error(226, line_num, line)
                lines[line_num] = re.sub(r'/\*.*?\*/', '', line)

        # 把单行模式, 代码行模式, 全部代空后, 只剩下多行模式的注释, 包括新行的多行模式, 和跨代码行的多行模式.
        start_line = None # 记录是否已找到一个多行注释的起始行.
        for line_num in self.LINES_ITERATOR:
            line = lines[line_num]
            if MULIT_LINE_MODE_START_PATTERN.search(line): # 检查是否为多行模式的起始行
                if not MULIT_LINE_MODE_START_RULE_PATTERN.match(line): # 检查规范
                    self._output_error(227, line_num, line)
                start_line = line_num # 标记已找到注释起始行, 后面开始匹配中间行和结束行

                # 检查多行模式开始行的缩进, 从上到下, 本行与下一行比较
                if self._count_space_on_the_left_side(line) + 1 != self._count_space_on_the_left_side(lines[line_num + 1]):
                    self._output_error(228, line_num, line)

                # 将注释替换成空白, 注意"/*"前面可能有代码.
                lines[line_num] = re.sub(r'/\*.*$', '', line)
                continue # 寻找下一行, 不能在开始行匹配中间行和结束行规则

            # 已经找到了注释开始行, 开始匹配中间行和结束行
            if start_line:
                line = lines[line_num]
                line_next = lines[line_num + 1]
                line_next_striped = line_next.strip()
                if not MULIT_LINE_MODE_STOP_PATTERN.search(line): # 中间行(不是结束行)
                    if not MULIT_LINE_MODE_MID_RULE_PATTERN.match(line): # 检查中间行规则
                        self._output_error(229, line_num, line)

                    # 检查多行模式的中间行缩进, 从上到下, 本行与下一行比较
                        if self._count_space_on_the_left_side(line) != self._count_space_on_the_left_side(line_next):
                            self._output_error(230, line_num, line)

                    lines[line_num] = '' # 直接将中间行替换为空白
                else: # 结束行
                    if not MULIT_LINE_MODE_STOP_RULE_PATTERN.match(line): # 检查结束行规则
                        self._output_error(231, line_num, line)

                    """
                    检查多行模式的结束行缩进, 从上到下, 本行与下一行比较
                    若下一行不为空(有代码), 则此多行注释应匹配代码行缩进

                    当下一行为空, 则此多行注释应该为顶行注释(所以如果此多行注释在{}, 则注释末行的下一行, 一定不能为空)
                        当下一行为空时.由于之前已经将"//"和单行模式的"/**/"都替换为空了, 所以此处下一行也有可能是被置换为空的那行(原先为单行注释).
                        所以多行模式, 紧接下一行, 如果为单行注释, 这种情况是不允许的.
                    """
                    if line_next_striped: # 下一行不为空
                        if self._count_space_on_the_left_side(line) != self._count_space_on_the_left_side(line_next) + 1:
                            self._output_error(232, line_num, line)
                    else:
                        if self._count_space_on_the_left_side(line) != 1:
                            self._output_error(233, line_num, line)

                    start_line = None # 注释已经结束, 重置起始标志, 便于下一个注释的查找.

                    # 将注释替换为空白, 注意'*/'后面可能还有代码, 使用非贪婪模式
                    lines[line_num] = re.sub(r'.*?\*/', '', line)

        self.lines_without_all_comments = lines.copy()


    def _check_unsafe_memory_opration_funciton(self):
        if _CHECK_ITEM_SECURE_FUNC in self.lint_configs:
            logger.debug("_check_unsafe_memory_opration_funciton!!!")
            _UNSAFE_FUNC_RE_PATTERN = "(memcpy|memmove|memset|snprintf|sprintf|sscanf|strcat|strcpy|strncat|strncpy|strtok|vsnprintf|vsprintf|vsscanf)"
            _UNSAFE_FUNC_RE_PATTERN_CONPILED = re.compile(_UNSAFE_FUNC_RE_PATTERN + r"\(")
            lines = self.lines_without_all_comments.copy()
            for line_num in self.LINES_ITERATOR:
                line = lines[line_num]
                if _UNSAFE_FUNC_RE_PATTERN_CONPILED.search(line):
                    self._output_error(251, line_num, line)


    def _findout_multi_line_with_blackslash(self, lines, start_line_num, stop_line_num):
        """寻找以反斜杠'\\'为多行的块

        Args:
            lines:              所有行的list
            start_line_num:     查找起始行
            stop_line_num:      查找结束行
        """
        if not lines[start_line_num].strip(): # 第一行为空, 直接返回
            return None
        for line_num in range(start_line_num, stop_line_num + 1):
            if lines[line_num].strip(): # 使用list[-1]时, 此行不能为空
                if lines[line_num].strip()[-1] != '\\': # 此行不为空, 且最后一个字符不是'\\'时, 说明多行结束
                    return line_num
            else: # 此行为空, 说明书写格式有问题，上一行已经结束
                return line_num - 1
        return start_line_num


    def _save_construct_info_and_replace_line_with_blank(self, construct_info: list, lines, start_line, brackets_start_line, stop_line, depth):
        """按格式保存enum, fuction, union,  struct等结构的信息

        XXX_CONSTRUCT_INFO
            enum, function, struct, union等定义的结构信息
            type: list[{dict}, {dict}, {dict}]
            {
                'line_start':     int   # The start line num of the construct, sometimes before the brackets start line.
                'brackets_start': int   # The start line num of the brackets.
                'line_stop':      int   # The end line num of the construct.
                'depth':          int   # The max depth of the construct, represent how many '{}' it has.
                'data':           list  # The data in line of the whole construct.
            }

        Args:
            construct_info: list, 指向实际的construct列表, 如_FUNCTION_CONSTRUCT_INFO等
            lines: list, 当前文件中所有行的信息(已经处理过的, 如去掉了注释, 字符串等)
            start_line: int, 整体结构的起始行数, 一般与"{"在同一行或者上一行.
            brackets_start_line: int, "{"的开始行数
            stop_line: int, 整体结构的结束行
            depth: int, 整体结构的'{}'嵌套深度
        """
        construct_data = lines[start_line : stop_line + 1]
        construct_dict = {
            "line_start": start_line,
            "brackets_start": brackets_start_line,
            "line_stop": stop_line,
            "depth": depth,
            "data": construct_data,
        }
        # construct_info.append((start_line, brackets_start_line, stop_line, depth, construct_data))
        construct_info.append(construct_dict)
        for line_num in range(start_line, stop_line + 1): # 已找到的construct信息已经保存, 之后基于保存的信息继续处理, 替换原始lines中对应位置为空, 不影响行数量.
            lines[line_num] = ''


    def _check_hash_if_and_replace_by_blank(self):
        """检查宏书写规范.
        1. 每行顶格书写: '#if' 前不能有空格.
        2. 需要顶格书写的有: '#if', '#elif', '#else', '#endif'
        TODO: 3. 检查宏命名规范: 全部只包含大写英文字母[A-Z]和下划线[_]
                4. #if 后可能有注释, 是否需要在注释检查完后检查此项
                5. 有些'{}'在#if里面, 导致'{'和'}'数量不等

        Errors:
            category: [whitespace/hash_if_format]
            confidence: [5]
            message: [Marco format error: no indentation before "#" symbol."]

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        # rule = re.compile(r'\s+(#if|#endif|#elif|#define)')
        # for line_num in range(_tws_lint_state.LINE_LENS_RANGE_START, _tws_lint_state.LINE_LENS_RANGE_STOP):
        #   if rule.match(lines[line_num]):
        #     _Error(filename, line_num, 'whitespace/marco', 5,
        #       'Marco format error: no indentation before "#" symbol.')
        _HASH_IF_PATTERN = re.compile(r'\s*#if|#elif|#else|#endif')
        lines = self.lines_without_all_comments.copy()
        for line_num in self.LINES_ITERATOR:
            line = lines[line_num]
            start_line = 0
            stop_line = 0
            if _HASH_IF_PATTERN.search(line):
                start_line = line_num
                if self._count_space_on_the_left_side(line) > 0:
                    self._output_error(252, line_num, line)
                stop_line = self._findout_multi_line_with_blackslash(lines, start_line, self.LINES_COUNT_RANGE_STOP)
                self._save_construct_info_and_replace_line_with_blank(self.construct_info_hash_if_list, lines, start_line, start_line, stop_line, 1)
        self.lines_without_all_comments_and_hash_if = lines.copy()


    def _check_hash_define_and_replace_by_blank(self):
        """检查'#define'书写规范, 并将其替换为空行
        1. 每行顶格书写
        2. 多行模式最后一行不应有\
        3. #define与宏之间, 只能有一个空格
        4. #define后的宏, 应全部大写
        TODO: 3. 检查规范
                    4. #define 后可能有注释, 是否需要在注释检查完后检查此项

        Errors:
            category: [whitespace/hash_define_format]
            confidence: [5]
            message: []

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        _HASH_DEFINE_PATTERN = re.compile(r'\s*#define')
        line_num = self.LINES_COUNT_RANGE_START
        lines = self.lines_without_all_comments_and_hash_if.copy()
        while line_num <= self.LINES_COUNT_RANGE_STOP:
            line = lines[line_num]
            start_line = 0
            stop_line = 0
            if _HASH_DEFINE_PATTERN.search(line):
                start_line = line_num

                #检查 顶格判断 at 0227,start!
                if self._count_space_on_the_left_side(line) > 0:
                    self._output_error(252, line_num, line)
                #检查 顶格判断 at 0227,end!!!

                stop_line = self._findout_multi_line_with_blackslash(lines, start_line, self.LINES_COUNT_RANGE_STOP)
                self._save_construct_info_and_replace_line_with_blank(self.construct_info_hash_define_list, lines, start_line, start_line, stop_line, 1)
                # if line.strip()[-1] != '\\': # 单行模式
                #   stop_line = start_line
                #   _SaveConstructInfoAndReplaceLineWithBlank(_tws_lint_state.HASH_DEFINE_CONSTRUCT_INFO, lines, start_line, start_line, stop_line, 1)
                #   line_num += 1
                #   continue
                # else: #多行模式
                #   for i in range(line_num, _tws_lint_state.LINE_LENS_RANGE_STOP):
                #     if lines[i].strip(): # 此行不为空
                #       if lines[i].strip()[-1] != '\\': # 找到结束行
                #         stop_line = i
                #         _SaveConstructInfoAndReplaceLineWithBlank(_tws_lint_state.HASH_DEFINE_CONSTRUCT_INFO, lines, start_line, start_line, stop_line, 1)
                #         line_num = i + 1
                #         break
                #     else: # 此行为空, 说明格式有问题, 但确实已经结束
                #       stop_line = i - 1
                #       _SaveConstructInfoAndReplaceLineWithBlank(_tws_lint_state.HASH_DEFINE_CONSTRUCT_INFO, lines, start_line, start_line, stop_line, 1)
                #       line_num = i
                #       break
                #   continue
            line_num += 1
        self.lines_without_all_comments_and_hash_if_and_hash_define = lines.copy()


    def _check_include_format(self):
        """检查'#include'格式.
        1. '#include'顶行写, 前面不能有空格.
        2. '#include'后只有一个空格, 不能有多个空格
        3. 需要使用双引号, 不使用尖括号: 正确: '#include "xxx.h"',  错误: '#include <xxx.h>'
        4. 不能带路径.错误: '#include "../aaa/bbb/xxx.h"'
        TODO: 同一个客户的头文件放在一起.比如Green客户的头文件, 都带'green_'前缀, 需要放到一起.

        Errors:
            category: [whitespace/include]
            confidence: [5]
            message: ["#include" format error. syntax: #include "xxx.h", without file path]

        Args:
            filename: 需要处理的文件名.
            file_extention: filename的文件扩展类型, 不含'.'符号, 如'c', 'h'等.
            lines: filename中的所有行列表[].
        """
        _INCLUDE_PATTERN = re.compile(r'^\s*#include')
        _INCLUDE_FORMAT_PATTERN = re.compile(r'^#include "[^..].*\.h"$')
        lines = self.lines_without_all_comments_and_hash_if_and_hash_define.copy()
        for line_num in self.LINES_ITERATOR:
            line = lines[line_num]
            if _INCLUDE_PATTERN.match(line):
                if not _INCLUDE_FORMAT_PATTERN.match(line):
                    self._output_error(253, line_num, line)
                self._save_construct_info_and_replace_line_with_blank(self.construct_info_include_list, lines, line_num, line_num, line_num, 1)


    def _findout_string_and_replace_by_blank(self):
        """查找字符串, 并使用一个固定的symbol替代, 消除对后续检查的影响.
        1. 单引号字符串
        2. 多引号字符串
        3. 替换为'STRING'
        4. 多行字符串, 每行都应使用"", 不使用"加换行符的形式.
        TODO: 1. 限制Log中字符串长度
                    2. Log字符串中, 不应有__func__, __line__等宏
                    3. 字符串中的,;等字符, 是否需要检查规则
        """
        _CHAR_PATTERN = re.compile(r'\'.*\'')
        _SINGLE_LINE_STRING_PATTERN = re.compile(r'\".*\"')
        _MULTI_LINE_STRING_PATTERN = re.compile(r'\"|\'')
        _MULTI_LINE_STRING_START_REPLACE_PATTERN = re.compile(r'\".*\\$')
        _MULTI_LINE_STRING_MID_REPLACE_PATTERN = re.compile(r'\S.*$')
        _MULTI_LINE_STRING_STOP_REPLACE_PATTERN = re.compile(r'\S.*\"')
        _EXTERN_C_PATTERN = re.compile(r'^\s*extern\s*"C"')
        multi_line_start = None
        multi_line_stop = None
        lines = self.lines_without_all_comments_and_hash_if_and_hash_define.copy()
        for line_num in self.LINES_ITERATOR:
            line = lines[line_num]
            if _EXTERN_C_PATTERN.match(line):
                continue
            if _CHAR_PATTERN.search(lines[line_num]): # 首先替换掉单引号的char类型, 此类型不能跨行, 但是包含所有的字符符号（包括", +等）
                lines[line_num] = re.sub(_CHAR_PATTERN, '_CHAR', lines[line_num])
            if _SINGLE_LINE_STRING_PATTERN.search(lines[line_num]): # 然后替换掉单行的"字符串"
                lines[line_num] = re.sub(_SINGLE_LINE_STRING_PATTERN, '_STRING', lines[line_num])
            if _MULTI_LINE_STRING_PATTERN.search(lines[line_num]): # 经过上面两次替换后, 如果还有引号,说明有跨行的字符串, 但是跨行字符串应符合每行都有两个双引号.
                if not multi_line_start: # 多行字符串第一行
                    multi_line_start = line_num
                    # print('1', filename, line_num, line)
                    lines[line_num] = re.sub(_MULTI_LINE_STRING_START_REPLACE_PATTERN, '_STRING', lines[line_num])
                    # print('1', filename, line_num, lines[line_num])
                    continue
                else: # 多行字符串最后一行
                    multi_line_stop = line_num
                    # print('3', filename, line_num, line)
                    lines[line_num] = re.sub(_MULTI_LINE_STRING_STOP_REPLACE_PATTERN, '_STRING', lines[line_num])
                    # print('3', filename, line_num, lines[line_num])
                    multi_line_start = None
                    multi_line_stop = None
            if multi_line_start and not multi_line_stop: # 多行字符串中间行
                # print('2', filename, line_num, line)
                lines[line_num] = re.sub(_MULTI_LINE_STRING_MID_REPLACE_PATTERN, '_STRING', lines[line_num])
                # print('2', filename, line_num, lines[line_num])
            # elif multi_line_start and multi_line_stop:
            #   multi_line_start = None
            #   multi_line_stop = None
        self.lines_without_all_comments_and_hash_if_and_hash_define_and_string = lines.copy()


    def _findout_one_brackets_construct(self, construct_info, lines, linenum, label) -> int:
        """基于开始行, 整个construct行信息.

        Args:
            construct_info: list, 指向实际的construct列表, 如_FUNCTION_CONSTRUCT_INFO等
            lines: list, 当前文件中所有行的信息(已经处理过的, 如去掉了注释, 字符串等)
            linenum: int, 整体结构的起始行数, 也就是发现enum, function, struct, union的起始行.
        """
        # Notes: 结构定义可能有多行模式, 如：
        # static void PowerStateDischargeHeart(POWER_COMMONDATA_T *data, POWER_EDGE_DETECT_HANDLE_T *ocd, \
        #                               POWER_EDGE_DETECT_HANDLE_T *uvd, POWER_EDGE_DETECT_HANDLE_T *uv,\
        #                               POWER_EDGE_DETECT_HANDLE_T *uc)
        # {
        _FIND_ALL_BRACKETS_PATTERN = re.compile(r'[{}]')
        _LINE_STOP_PATTERN = re.compile(r';\s*$')
        _PARENTHESIS_START_PATTERN = re.compile(r'\(')
        _PARENTHESIS_STOP_PATTERN = re.compile(r'\)')
        _PARENTHESIS_PATTERN = re.compile(r'[()]')
        first_line = lines[linenum]
        brackets_start_line = None

        if label == self.construct_info_function_lable: # 函数声明单独处理
            if re.match(r'^\s*typedef', first_line):
                return 1
            if len(_PARENTHESIS_START_PATTERN.findall(first_line)) > len(_PARENTHESIS_STOP_PATTERN.findall(first_line)): # 函数"()"中参数列表为多行模式
                start_line = linenum
                stop_line = 0
                depth = 0
                for i in range(start_line, self.LINES_COUNT_RANGE_STOP):
                    for iter in _PARENTHESIS_PATTERN.finditer(lines[i]): # 需要计算'('和')'的个数。
                        if iter.group() == '(':
                            depth += 1
                        elif iter.group() == ')':
                            depth -= 1
                        if depth == 0: # 找到了完整的参数列表
                            stop_line = i
                            break
                    if stop_line != 0: # 当找到了完整的参数列表, 判断是否为函数声明
                        if lines[stop_line].strip()[-1] == ';':
                            self._save_construct_info_and_replace_line_with_blank(self.construct_info_function_statement_list, lines, start_line, start_line, stop_line, 0)
                            return stop_line - start_line + 1
                        else:
                            break
            elif lines[linenum].strip()[-1] == ';':
                start_line = linenum
                stop_line = linenum
                self._save_construct_info_and_replace_line_with_blank(self.construct_info_function_statement_list, lines, start_line, start_line, stop_line, 0)
                return stop_line - start_line + 1
        if label == self.construct_info_variable_define_label:
            if lines[linenum].strip()[-1] == ';':
                start_line = linenum
                stop_line = linenum
                self._save_construct_info_and_replace_line_with_blank(self.construct_info_variable_define_list, lines, start_line, start_line, stop_line, 0)
                return stop_line - start_line + 1

        if (not _FIND_ALL_BRACKETS_PATTERN.search(first_line)) and _LINE_STOP_PATTERN.search(first_line): # 第一行没有'{'或'}'符号, 且末尾有';', 说明此行是变量定义
            return 1

        depth = 0
        max_depth = 0
        for line_num in range(linenum, self.LINES_COUNT_RANGE_STOP):
            line = lines[line_num]
            if _FIND_ALL_BRACKETS_PATTERN.search(line):
                if not brackets_start_line:
                    brackets_start_line = line_num
                for iter in _FIND_ALL_BRACKETS_PATTERN.finditer(line):
                    if iter.group() == '{':
                        depth += 1
                        max_depth += 1
                    elif iter.group() == '}':
                        if depth > 1:
                            depth -= 1
                        else:
                            stop_line = line_num
                            # construct_lines = lines[linenum: stop_line + 1]
                            # construct_info.append((linenum, start_line, stop_line, max_depth, construct_lines))
                            self._save_construct_info_and_replace_line_with_blank(construct_info, lines, linenum, brackets_start_line, stop_line, max_depth)
                            return (stop_line - linenum + 1)

        # _FIND_ALL_BRACKETS_PATTERN = re.compile(r'[{}]')
        # _BRACKETS_IN_ONE_LINE_PATTERN = re.compile(r'{.*}')
        # _BRACKETS_START_PATTERN = re.compile(r'{')
        # _BRACKETS_STOP_PATTERN = re.compile(r'}')
        # _LINE_STOP_PATTERN = re.compile(r';\s*$')
        # _BRACKETS_IN_SINGLE_LINE_MODE_PATTERN = re.compile(r'') #
        # first_line = lines[linenum]
        # second_line = lines[linenum + 1]
        # start_line = None
        # depth = 0
        # max_depth = 0
        # if _BRACKETS_IN_ONE_LINE_PATTERN.search(first_line): # '{}'同在第1行, 检查了1行
        #   # construct_lines = lines[linenum: linenum + 1]
        #   # construct_info.append((linenum, linenum, linenum, 1, construct_lines))
        #   _SaveConstructInfoAndReplaceLineWithBlank(construct_info, lines, linenum, linenum, linenum, 1)
        #   return 1
        # if (not _BRACKETS_IN_ONE_LINE_PATTERN.search(first_line)) and _LINE_STOP_PATTERN.search(first_line): # 第一行没有'{}', 但有';', 说明不是一个类型定义或结构, 检查了1行
        #   return 1 # 先检查完第一行, 再检查第二行
        # if _BRACKETS_IN_ONE_LINE_PATTERN.search(second_line): # '{}'同在第2行, 检查了1行
        #   # construct_lines = lines[linenum: linenum + 2]
        #   # construct_info.append((linenum, linenum + 1, linenum + 1, 1, construct_lines))
        #   _SaveConstructInfoAndReplaceLineWithBlank(construct_info, lines, linenum, linenum + 1, linenum + 1, depth)
        #   return 2

        # if _BRACKETS_START_PATTERN.search(first_line): # '{'在第一行
        #   start_line = linenum
        #   # depth = 1
        # elif _BRACKETS_START_PATTERN.search(second_line): # '{'在第二行
        #   start_line = linenum + 1
        #   # depth = 1
        # else: # 不是一个'{}'类型定义或结构, 因为第一行和第二行都没有, 检查了1行
        #   return 1

        # if start_line:
        #   depth = 1
        #   max_depth = 1
        #   for line_num in range(start_line + 1, _tws_lint_state.LINE_LENS_RANGE_STOP):
        #     line = lines[line_num]
        #     if _FIND_ALL_BRACKETS_PATTERN.search(line):
        #       for iter in _FIND_ALL_BRACKETS_PATTERN.finditer(line):
        #         if iter.group() == '{':
        #           depth += 1
        #           max_depth += 1
        #         elif iter.group() == '}':
        #           if depth > 1:
        #             depth -= 1
        #           else:
        #             stop_line = line_num
        #             # construct_lines = lines[linenum: stop_line + 1]
        #             # construct_info.append((linenum, start_line, stop_line, max_depth, construct_lines))
        #             _SaveConstructInfoAndReplaceLineWithBlank(construct_info, lines, linenum, start_line, stop_line, max_depth)
        #             return (stop_line - linenum + 1)

        return 1


    def _findout_all_multi_line_block(self):
        """找出所有的多行主体"{}"结构, 包括fuction, enum, struct, union.
        只寻找最外层结构, 如果内部有嵌套, 嵌套内容属于最外一层的结构.
        example: 此处寻找到的是enum1这个整体结构, 内部包含了enum2和enum3
            enum1 {
                ...
                enum2 {
                    ...
                    enum3 {
                        ...
                    }
                }
                ...
            }
        """
        _ENUM_PATTERN = re.compile(r'^\s*(typedef\b)?\s*enum\b\s*')
        _STRUCT_PATTERN = re.compile(r'^\s*(typedef\b)?\s*struct\b\s*')
        _UNION_PATTERN = re.compile(r'^\s*(typedef\b)?\s*union\b\s*')
        # _FUNCTION_PATTERN = re.compile(r'\w+(\s|\n|\*)+\w+(\s|\n)*\((\s|\n|!|%|&|\(|\)|\*|\+|,|-|\/|\w|\[|\\|\]|\^|\||~|<{2}|>{2})*?\)(\n|\s)*')
        _FUNCTION_PATTERN = re.compile(r'\w+(\s|\n|\*)+\w+(\s|\n)*\((\s|\n|!|%|&|\(|\)|\*|\+|,|-|\/|\w|\[|\\|\]|\^|\||~|<{2}|>{2})*?(\n|\s*)')
        _VARIABLE_DEFINE_PATTERN = re.compile(r'\s*[a-zA-Z0-9_]+(\[.*\])*\s*=\s*{*')
        # _VARIABLE_DEFINE_PATTERN2 = re.compile(r'\s*[a-zA-Z0-9_]+(\[.*\])*\s*=\s*{*')
        #extern "C" 处理
        # for line_num in range(_tws_lint_state.LINE_LENS_RANGE_START, _tws_lint_state.LINE_LENS_RANGE_STOP):
        line_num = self.LINES_COUNT_RANGE_START
        lines = self.lines_without_all_comments_and_hash_if_and_hash_define_and_string.copy()
        while line_num <= self.LINES_COUNT_RANGE_STOP:
            line = lines[line_num]
            checked_line_count = 1
            if line.strip():
                if _FUNCTION_PATTERN.search(line):
                    checked_line_count = self._findout_one_brackets_construct(self.construct_info_function_list, lines, line_num, self.construct_info_function_lable)
                elif _ENUM_PATTERN.match(line):
                    checked_line_count = self._findout_one_brackets_construct(self.construct_info_enum_list, lines, line_num, self.construct_info_enum_label)
                elif _STRUCT_PATTERN.match(line):
                    checked_line_count = self._findout_one_brackets_construct(self.construct_info_struct_list, lines, line_num, self.construct_info_struct_label)
                elif _UNION_PATTERN.match(line):
                    checked_line_count = self._findout_one_brackets_construct(self.construct_info_union_list, lines, line_num, self.construct_info_union_label)
                elif _VARIABLE_DEFINE_PATTERN.search(line):
                    checked_line_count = self._findout_one_brackets_construct(self.construct_info_variable_define_list, lines, line_num, self.construct_info_variable_define_label)
            line_num = line_num + checked_line_count
        self.lines_without_all_comments_and_hash_if_and_hash_define_and_string_and_constructs = lines.copy()


    def _check_struct_rules(self):
        _INDENT_SPACE_COUNT = 4
        _COMMA_RULE_PATTERN = re.compile(r'\s+,') # 当逗号前面没有空格
        _COMMA_RULE_PATTERN2 = re.compile(r',(\S|\s\s+\S)') # 当逗号后面没有空格，或者有两个以上空格时
        _COMMA_RULE_PATTERN3 = re.compile(r",\S") # 当逗号后面没有空格时
        _SEMICOLON_RULE_PATTERN = re.compile(r'\s+;') # 当分号前有一个或多个空格
        _PARENTHESIS_SQUAREBRACKETS_RULE_PATTERN = re.compile(r'\(\s|\s\)|\[\s|\s\]') # 圆括号和方括号,与内部字符之间，不应有空格
        _LEFT_BRACE_RULE_PATTERN = re.compile(r'\S\{|\S\s\s+\{|\{\s*\S')
        _RIGHT_BRACE_RULE_PATTERN = re.compile(r'\S\s*\}|\}(\w|\s\s+)')
        _STRUCT_NAME_PATTERN1 = re.compile(r'(?<=struct).+(?={)') # 第一行如果有定义结构体名称
        _STRUCT_NAME_PATTERN2 = re.compile(r'(?<=\))\s*\w+(\s*,\s*\w+\s*)*\s*(?=;)') # 如果最后一行有圆括号
        _STRUCT_NAME_PATTERN3 = re.compile(r'(?<=\})\s*\w+(\s*,\s*\w+\s*)*\s*(?=;)') # 最后一行没有圆括号
        for item in self.construct_info_struct_list:
            if item:
                current_indent_count = 0
                error_count = 0
                first_line = item['data'][0]
                last_line = item['data'][-1]
                first_line_num = item['line_start']
                last_line_num = item['line_stop']
                for line_num in range(0, len(item['data'])):
                    raw_line_num = line_num + item['line_start']
                    line = item['data'][line_num]
                    striped_line = line.strip()

                    # 当本行最后为'}'时，缩进减1, 每多一个"}", 缩进减_INDENT_SPACE_COUNT
                    if len(re.findall(r'{', line)) < len(re.findall(r'}', line)):
                        current_indent_count -= _INDENT_SPACE_COUNT

                    if (self._count_space_on_the_left_side(line) != current_indent_count) and (line.strip()):
                        self._output_error(300, raw_line_num, line)
                        error_count += 1

                    # 检查花括规范
                    if (line.find('{') != -1) and (_LEFT_BRACE_RULE_PATTERN.search(line) or (striped_line == '{')):
                        self._output_error(301, raw_line_num, line)
                        error_count += 1
                    elif (line.find('}') != -1) and (_RIGHT_BRACE_RULE_PATTERN.search(line) or (striped_line == '}')):
                        self._output_error(302, raw_line_num, line)
                        error_count += 1

                    if _COMMA_RULE_PATTERN.search(striped_line) or _COMMA_RULE_PATTERN3.search(striped_line):
                        self._output_error(303, raw_line_num, line)
                        error_count += 1
                    elif _SEMICOLON_RULE_PATTERN.search(striped_line):
                        self._output_error(304, raw_line_num, line)
                        error_count += 1
                    elif _PARENTHESIS_SQUAREBRACKETS_RULE_PATTERN.search(striped_line):
                        self._output_error(305, raw_line_num, line)
                        error_count += 1

                    # 检查结构体成员对齐规则
                    # 检查结构体成员驼峰格式
                    # 第一排和最后一排无缩进
                    # struct 命名之间只有一个空格

                    # 当本行最后为'{'时，下一行缩进加1. 由于是逐行检查，且第一行缩进永远为0，所以需要将此判断放到最后
                    # if len(re.findall(r'{', line)) > len(re.findall(r'}', line)):
                    if re.findall(r'{', line) > re.findall(r'}', line):
                        current_indent_count += _INDENT_SPACE_COUNT

                # 检查结构体命名, 当花括号符合规则时再匹配, 否则容易匹配错误
                if error_count == 0:
                    # struct_name_list = []
                    name = _STRUCT_NAME_PATTERN1.search(first_line)
                    if name:
                        name = name.group().split(',')
                        for i in name:
                            i = i.strip()
                            if i.strip() != '':
                                # struct_name_list.append(i.strip())
                                if (not i.isupper()) or (i[-2:] != '_T'):
                                    self._output_error(306, first_line_num, first_line)

                    if last_line.find(')') != -1:
                        name = _STRUCT_NAME_PATTERN2.search(last_line)
                    else:
                        name = _STRUCT_NAME_PATTERN3.search(last_line)
                    if name:
                        name = name.group().split(',')
                        for i in name:
                            if i.strip() != '':
                                # struct_name_list.append(i.strip())
                                if (not i.isupper()) or (i[-2:] != '_T'):
                                    self._output_error(307, last_line_num, last_line)

                    # for name in struct_name_list:
                    #   if (not name.isupper()) or (name[-2:] != '_T'):
                    #     _Error(filename, raw_line_num, 'struct/name', 5,
                    #       'Struct name format error.')
                    #     break


    def _check_enum_rules(self):
        _INDENT_SPACE_COUNT = 4
        _COMMA_RULE_PATTERN = re.compile(r'\s+,') # 逗号前面没有空格, 整个enum都检查
        _COMMA_RULE_PATTERN2 = re.compile(r',(\S|\s\s+)') # 逗号后面没有空格或有一个以上的空格, 只检查含有'{'或'}'的行
        _COMMA_RULE_PATTERN3 = re.compile(r',\S') # 逗号后面至少有1个空格
        _SEMICOLON_RULE_PATTERN = re.compile(r'\s+;') # 当分号前有一个或多个空格 #add at 0227
        _LEFT_BRACE_RULE_PATTERN = re.compile(r'\S\{|\S\s\s+\{|\{\s*\S') # 枚举名与"{"之间, 没有空格, 或者有2个及以上空格, 或者"{"后面没有换行
        _RIGHT_BRACE_RULE_PATTERN = re.compile(r'\S\s*\}|\}(\w|\s\s+)') # 右花括号应位于新行(前面没有空格), 右花括号后面不是分号时, 应与字符间有且仅有1个空格
        _ENUM_NAME_PATTERN1 = re.compile(r'(?<=enum).+(?={)') # 第一行如果有定义结构体名称
        _ENUM_NAME_PATTERN2 = re.compile(r'(?<=\))\s*\w+(\s*,\s*\w+\s*)*\s*(?=;)') # 如果最后一行有圆括号
        _ENUM_NAME_PATTERN3 = re.compile(r'(?<=\})\s*\w+(\s*,\s*\w+\s*)*\s*(?=;)') # 最后一行没有圆括号
        _OPERATER_RULE_PATTERN1 = re.compile(r'(\S|\s\s+)[\=\-\+]') # 运算符规则'=' '-' '+', 运算符前面有且仅有一个空格
        _OPERATER_RULE_PATTERN3 = re.compile(r'\S[\=\-\+]') # 运算符规则'=' '-' '+' # 运算符前有1个及以上的空格
        _OPERATER_RULE_PATTERN2 = re.compile(r'[\=\+](\S|\s\s+)') # 运算符规则'=' '+' # 负号运算符会导致误报 # 运算符后有且仅有一个空格
        _OPERATER_RULE_PATTERN4 = re.compile(r'[\=\+](\S|\s\s+)') # 运算符规则'=' '+' # 负号运算符会导致误报 # 运算符后有1个及以上的空格
        _HEX_DIGITS_PATTERN = re.compile(r'0[xX][0-9a-fA-F]+')
        for item in self.construct_info_enum_list:
            if item:
                current_indent_count = 0
                error_count = 0
                first_line = item['data'][0]
                last_line = item['data'][-1]
                first_line_num = item['line_start']
                last_line_num = item['line_stop']
                for line_num in range(0, len(item['data'])):
                    raw_line_num = line_num + item['line_start']
                    line = item['data'][line_num]
                    striped_line = line.strip()
                    if not striped_line: # 空行不做处理
                        continue
                    # 当本行最后为'}'时，缩进减1
                    if len(re.findall(r'{', line)) < len(re.findall(r'}', line)):
                        current_indent_count -= _INDENT_SPACE_COUNT
                        if _COMMA_RULE_PATTERN2.search(line): # 两个enum名间的逗号, 逗号后有且仅有一个空格
                            self._output_error(400, raw_line_num, line)

                    if (self._count_space_on_the_left_side(line) != current_indent_count) and (line.strip()):
                        self._output_error(401, raw_line_num, line)
                        error_count += 1

                    # 检查花括规范
                    if (line.find('{') != -1) and (_LEFT_BRACE_RULE_PATTERN.search(line) or (striped_line == '{')):
                        self._output_error(402, raw_line_num, line)
                        error_count += 1
                    elif (line.find('}') != -1) and (_RIGHT_BRACE_RULE_PATTERN.search(line) or (striped_line == '}')):
                        self._output_error(403, raw_line_num, line)
                        error_count += 1

                    if _COMMA_RULE_PATTERN.search(striped_line):
                        self._output_error(404, raw_line_num, line)
                        error_count += 1

                    elif _SEMICOLON_RULE_PATTERN.search(striped_line):
                        self._output_error(304, raw_line_num, line)
                        error_count += 1


                    # 检查enum成员对齐规则
                    # 检查enum成员驼峰格式
                    # enum和'{'或者名称之间应只有一个空格
                    # 最后一个成员, 末尾是否一定需要','

                    if (line.find('{') == -1) and (line.find('}') == -1) and (line_num != 0) and (line_num != len(item['data']) - 1):
                        if not _HEX_DIGITS_PATTERN.sub('_HEXDIG', line).isupper(): # 成员名应该全部大写  # '=' 号后面可能会有十六进制的0x符号，这里没必要要求大写
                            self._output_error(405, raw_line_num, line)

                    if _OPERATER_RULE_PATTERN3.search(line) or _OPERATER_RULE_PATTERN2.search(line): # 检查 '+' '-' '='之间的规则, 前后有且只有一个空格
                        self._output_error(406, raw_line_num, line)

                    # 当本行最后为'{'时，下一行缩进加1. 由于是逐行检查，且第一行缩进永远为0，所以需要将此判断放到最后
                    if len(re.findall(r'{', line)) > len(re.findall(r'}', line)):
                        current_indent_count += _INDENT_SPACE_COUNT
                        if _COMMA_RULE_PATTERN2.search(line): # 两个名称间的逗号, 逗号后应有一个空格
                            self._output_error(407, raw_line_num, line)


                # 检查enum命名, 当花括号符合规则时再匹配, 否则容易匹配错误
                if error_count == 0:
                    # struct_name_list = []
                    name = _ENUM_NAME_PATTERN1.search(first_line)
                    if name:
                        name = name.group().split(',')
                        for i in name:
                            if i.strip() != '':
                                i = i.strip() # 解析出来的name带有空格，需要先strip
                                if (not i.isupper()) or (i[-2:] != '_E'):
                                    self._output_error(408, first_line_num, first_line)
                                    break
                                # struct_name_list.append(i.strip())

                    if last_line.find(')') != -1:
                        name = _ENUM_NAME_PATTERN2.search(last_line)
                    else:
                        name = _ENUM_NAME_PATTERN3.search(last_line)
                    if name:
                        name = name.group().split(',')
                        for i in name:
                            if i.strip() != '':
                                if (not i.isupper()) or (i[-2:] != '_E'):
                                    self._output_error(409, last_line_num, last_line)
                                    break
                                # struct_name_list.append(i.strip())

                    # for name in struct_name_list:
                    #   if (not name.isupper()) or (name[-2:] != '_E'):
                    #     _Error(filename, raw_line_num, 'enum/name', 5,
                    #       'ENUM name format error.')
                    #     break


    def _check_union_rules(self):
        _SPACE_RULE_PATTERN = re.compile(r'\s\s+') # 任意两个符号之间，空白字符不能超过1个
        _COMMA_RULE_PATTERN = re.compile(r'\s+,') # 当逗号前面没有空格
        _COMMA_RULE_PATTERN2 = re.compile(r',(\S|\s\s+\S)') # 当逗号后面没有空格，或者有两个以上空格时
        _SEMICOLON_RULE_PATTERN = re.compile(r'\s+;') # 当分号前有一个或多个空格
        _BRACKETS_RULE_PATTERN = re.compile(r'\(\s|\s\)|\[\s|\s\]|\{\s|\s\}') # 括号与内部字符之间，不应有空格
        for item in self.construct_info_union_list:
            if item:
                for line_num in range(0, len(item['data'])):
                    raw_line_num = line_num + item['line_start']
                    line = item['data'][line_num]
                    line_striped = line.strip()
                    # self._check_common_rules(line, raw_line_num)
                    if _SPACE_RULE_PATTERN.search(line_striped): # 任意两个符号之间，空白字符不能超过1个
                        self._output_error(500, raw_line_num, line)
                    elif _COMMA_RULE_PATTERN.search(line_striped) or _COMMA_RULE_PATTERN2.search(line_striped):
                        self._output_error(501, raw_line_num, line)
                    elif _SEMICOLON_RULE_PATTERN.search(line_striped):
                        self._output_error(502, raw_line_num, line)
                    elif _BRACKETS_RULE_PATTERN.search(line_striped):
                        self._output_error(503, raw_line_num, line)


    def _findout_multi_line_by_gived_characters(self, lines, start_line_num, stop_line_num, newline_char) -> dict:
        """
        Args:
            lines: The list which contain all the line data to check
            start_line_num: The first line number which end with newline character.
            stop_line_num: The max line number we can search.
            newline_char: The newline character which we need to identify.
        Return -> dict:
            multi_line_info['count']: The line count (how many lines) we had found.
            multi_line_info['combo']: The combo of the multi line.
        """
        first_line = lines[start_line_num]
        combo_line = ''
        total_line_count = 0
        multi_line_info = {'count':0, 'combo':''}
        if not first_line.strip():
            return multi_line_info
        if first_line.strip()[-1] != '\\':
            return multi_line_info
        combo_line = first_line.rstrip("\\")
        total_line_count += 1
        for line_num in range(start_line_num + 1, stop_line_num):
            total_line_count += 1
            line = lines[line_num]
            striped_line = line.strip()
            if striped_line:
                if striped_line[-1] == '\\':
                    combo_line += striped_line.rstrip('\\')
                else:
                    combo_line += striped_line
                    break
        multi_line_info['count'] = total_line_count
        multi_line_info['combo'] = combo_line
        return multi_line_info


    def _check_fuction_rules(self):
        _INDENT_SPACE_COUNT = 4
        _PARENTHESIS_SQUAREBRACKETS_RULE_PATTERN = re.compile(r'\(\s|\s\)|\[\s|\s\]') # 圆括号和方括号,与内部字符之间，不应有空格

        _IF_PATTERN = re.compile(r'^\bif\b') # 匹配包含'if'的行
        _IF_RULE_PATTERN = re.compile(r'^if \(.*\) {$')
        _ELIF_PATTERN = re.compile(r'\belse\s*if\b')
        _ELIF_RULE_PATTERN = re.compile(r'^} else if \(.*\) {$')
        _ELSE_PATTERN = re.compile(r'\belse\b')
        _ELSE_RULE_PATTERN = re.compile(r'^} else {$')

        _FOR_PATTERN = re.compile(r'\bfor\b')
        _FOR_RULE_PATTERN = re.compile(r'^for \(.*\) {$')

        _SWITCH_PATTERN = re.compile(r'\bswitch\b')
        _SWITCH_RULE_PATTERN = re.compile(r'^switch \(.*\) {$')
        _SWITCH_CASE_PATTERN = re.compile(r'\bcase\b')
        _SWITCH_CASE_RULE_PATTERN = re.compile(r'^case \S.*\S:$')
        _SWITCH_BREAK_PATTERN = re.compile(r'\bbreak\b')
        _SWITCH_BREAK_RULE_PATTERN = re.compile(r'^break;$')
        _SWITCH_DEFAULT_PATTERN = re.compile(r'\bdefault\b')
        _SWITCH_DEFAULT_RULE_PATTERN = re.compile(r'^default:$')

        _COMMA_SEMICOLON_MID_PATTERN = re.compile(r'\S\s*[,;]\s*\S')
        _COMMA_SEMICOLON_MID_RULE_PATTERN = re.compile(r'\S[,;] \S')
        _COMMA_SEMICOLON_END_PATTERN = re.compile(r'\S\s*[,;]\s*$')
        _COMMA_SEMICOLON_END_RULE_PATTERN = re.compile(r'\S[,;]$')

        _DOWHILE_DO_PATTERN = re.compile(r'\bdo\b')
        _DOWHILE_DO_RULE_PATTERN = re.compile(r'^do {$')
        _DOWHILE_WHILE_PATTERN = re.compile(r'\bwhile\b.*;$')
        _DOWHILE_WHILE_RULE_PATTERN = re.compile(r'^} while \(.*\);$')

        _WHILE_PATTERN = re.compile(r'^\s*while\s*(.*)\s*{?(?!;)\s*$')
        _WHILE_RULE_PATTERN = re.compile(r'^while \(.*\) {$')

        _BRACE_PATTERN = re.compile(r'[{}]')
        _BRACE_END_RULE_PATTERN = re.compile(r'^}$')

        for item in self.construct_info_function_list:
            if item:
                first_line_num = item['line_start']
                last_line_num = item['line_stop']
                current_indent_count = 0
                error_count = 0
                first_line = item['data'][0]
                brace_start_line_num = item['brackets_start']
                brace_start_line = item['data'][brace_start_line_num - first_line_num]
                last_line = item['data'][-1]

                # 函数的起始'{', 应位于函数名的下一行, 且应为独立行.
                if brace_start_line.strip() != '{':
                    self._output_error(600, brace_start_line_num, brace_start_line)
                    error_count += 1

                # 函数的结束行'}', 应位于最后一行, 且应为独立行.
                if (last_line.strip() != '}'):
                    self._output_error(601, last_line_num, last_line)
                    error_count += 1

                # for line_num in range(0, len(item['data'])):
                line_num = 0
                while line_num < len(item['data']):
                    raw_line_num = line_num + item['line_start']
                    line = item['data'][line_num]
                    striped_line = line.strip()

                    # 检查'()' '[]'的规则
                    if _PARENTHESIS_SQUAREBRACKETS_RULE_PATTERN.search(line):
                        self._output_error(602, raw_line_num, line)
                        error_count += 1

                    if striped_line:
                        # 检查'if' 'else if' 'else' 单行语法
                        if _ELIF_PATTERN.search(striped_line):
                            temp_line = striped_line
                            if striped_line[-1] == '\\':
                                info = self._findout_multi_line_by_gived_characters(item['data'], line_num, item['line_stop'], '\\')
                                temp_line = info['combo'].strip()
                            if not _ELIF_RULE_PATTERN.search(temp_line):
                                self._output_error(603, raw_line_num, temp_line)
                                error_count += 1
                        elif _IF_PATTERN.search(striped_line):
                            # skip_check = 0
                            temp_line = striped_line
                            if striped_line[-1] == '\\':
                                info = self._findout_multi_line_by_gived_characters(item['data'], line_num, item['line_stop'], '\\')
                                temp_line = info['combo'].strip()
                                # line_num += info['count']
                                # skip_check = 1
                            if not _IF_RULE_PATTERN.search(temp_line):
                                self._output_error(604, raw_line_num, temp_line)
                                error_count += 1
                            # if skip_check == 1:
                            #   continue
                        elif _ELSE_PATTERN.search(striped_line):
                            if not _ELSE_RULE_PATTERN.search(striped_line):
                                self._output_error(605, raw_line_num, line)
                                error_count += 1

                        # 检查 'for'单行语法
                        if _FOR_PATTERN.search(striped_line):
                            if striped_line[-1] == '\\':
                                info = self._findout_multi_line_by_gived_characters(item['data'], line_num, item['line_stop'], '\\')
                                temp_line = info['combo'].strip()
                            else:
                                temp_line = striped_line
                            if not _FOR_RULE_PATTERN.search(temp_line):
                                self._output_error(606, raw_line_num, temp_line)
                                error_count += 1

                        # 检查 'switch' 'case' 'break' 'default'单行语法
                        if _SWITCH_PATTERN.search(striped_line):
                            if not _SWITCH_RULE_PATTERN.search(striped_line):
                                self._output_error(607, raw_line_num, line)
                                error_count += 1
                        elif _SWITCH_CASE_PATTERN.search(striped_line):
                            if not _SWITCH_CASE_RULE_PATTERN.search(striped_line):
                                self._output_error(608, raw_line_num, line)
                                error_count += 1
                        elif _SWITCH_BREAK_PATTERN.search(striped_line):
                            if not _SWITCH_BREAK_RULE_PATTERN.search(striped_line):
                                self._output_error(609, raw_line_num, line)
                                error_count += 1
                        elif _SWITCH_DEFAULT_PATTERN.search(striped_line):
                            if not _SWITCH_DEFAULT_RULE_PATTERN.search(striped_line):
                                self._output_error(610, raw_line_num, line)

                        # 检查 ',' ';'
                        if _COMMA_SEMICOLON_MID_PATTERN.search(striped_line):
                            for i in _COMMA_SEMICOLON_MID_PATTERN.finditer(striped_line):
                                if not _COMMA_SEMICOLON_MID_RULE_PATTERN.search(i.group()):
                                    self._output_error(611, raw_line_num, line)
                                    error_count += 1
                                    break
                        elif _COMMA_SEMICOLON_END_PATTERN.search(striped_line):
                            for i in _COMMA_SEMICOLON_END_PATTERN.finditer(striped_line):
                                if not _COMMA_SEMICOLON_END_RULE_PATTERN.search(i.group()):
                                    self._output_error(612, raw_line_num, line)
                                    error_count += 1
                                    break

                        # 检查'do-while' 'while' 单行语法
                        if _DOWHILE_DO_PATTERN.search(striped_line):
                            if not _DOWHILE_DO_RULE_PATTERN.search(striped_line):
                                self._output_error(613, raw_line_num, line)
                                error_count += 1
                        elif _DOWHILE_WHILE_PATTERN.search(striped_line):
                            if not _DOWHILE_WHILE_RULE_PATTERN.search(striped_line):
                                self._output_error(614, raw_line_num, line)
                                error_count += 1
                        elif _WHILE_PATTERN.search(striped_line):
                            if not _WHILE_RULE_PATTERN.search(striped_line):
                                self._output_error(615, raw_line_num, line)
                                error_count += 1

                    # 检查缩进
                    # copied_lines = item['data']
                    # _HandleAllMultiLineContext(copied_lines)
                    # brace_list = _FindAllBracePairs(item['data'])

                    # for brace_pair in brace_list:
                    #   start_line_num = brace_pair[0]
                    #   stop_line_num = brace_pair[1]
                    #   start_line = copied_lines[brace_pair[0]]
                    #   stop_line = copied_lines[brace_pair[1]]
                    #   if

                    # in_multi_line_context = False
                    # brace_depth = 0
                    # in_switch_case_context = False
                    # current_indent_count = _INDENT_SPACE_COUNT
                    # next_indent_count = _INDENT_SPACE_COUNT
                    # if (error_count == 0) and striped_line and (line_num > brace_start_line_num):
                    #   if striped_line[-1] == '\\':
                    #     next_indent_count = current_indent_count + _INDENT_SPACE_COUNT
                    #     in_multi_line_context = True
                    #   elif in_multi_line_context == True:
                    #     in_multi_line_context = False
                    #   if striped_line[-1] == '{':
                    #     next_indent_count = current_indent_count + _INDENT_SPACE_COUNT
                    #     brace_depth += 1
                    #     if _SWITCH_CASE_RULE_PATTERN.match(striped_line):
                    #       in_switch_case_context = True
                    #   elif _ELIF_RULE_PATTERN.match(striped_line):
                    #     next_indent_count = current_indent_count + _INDENT_SPACE_COUNT
                    #   elif _ELSE_RULE_PATTERN.match(striped_line):
                    #     next_indent_count = current_indent_count + _INDENT_SPACE_COUNT
                    #   elif striped_line == '}':
                    #     brace_depth -= 1
                    #     next_indent_count = current_indent_count - _INDENT_SPACE_COUNT
                    #   elif _DOWHILE_WHILE_RULE_PATTERN.match(striped_line):
                    #     next_indent_count = current_indent_count - _INDENT_SPACE_COUNT

                    #   if _CountLeftSpace(line) != current_indent_count:
                    #     _Error(filename, raw_line_num, 'function/indentation', 5,
                    #       'The indentation for this line should be %i space, but you have %i' % (current_indent_count, _CountLeftSpace(line)))
                    #   current_indent_count = next_indent_count

                    # 当本行最后为'}'时，缩进减1
                    # if (error_count == 0) and striped_line:
                    #   if striped_line[0] == '}':
                    #     current_indent_count -= _INDENT_SPACE_COUNT
                    #   temp_indent = 0
                    #   if raw_line_num > first_line_num:
                    #     previous_line = item['data'][line_num - 1]
                    #     striped_previous_line = previous_line.strip()
                    #     if striped_previous_line:
                    #       if striped_previous_line[-1] == '\\':
                    #         temp_indent = _INDENT_SPACE_COUNT
                    #   if (_CountLeftSpace(line) != current_indent_count + temp_indent) and striped_line:
                    #     _Error(filename, raw_line_num, 'function/indentation', 5,
                    #       'The indentation for this line should be %i space, but you have %i' % (current_indent_count + temp_indent, _CountLeftSpace(line)))

                    #   if striped_line[-1] == '{':
                    #     current_indent_count += _INDENT_SPACE_COUNT
                        # if _SWITCH_CASE_PATTERN.search(striped_line):
                        #   current_indent_count += _INDENT_SPACE_COUNT
                        # elif _SWITCH_BREAK_PATTERN.search(striped_line):
                        #   current_indent_count -= _INDENT_SPACE_COUNT
                        # elif _SWITCH_DEFAULT_PATTERN.search(striped_line):
                        #   current_indent_count += _INDENT_SPACE_COUNT

                    line_num += 1 # should be the last operation
                    # 局部变量驼峰格式
                    # 函数名驼峰格式
                    # 函数行数
                    # 函数名长度
                    # 检查参数个数
                    # if, for, while, switch, do-while
                    # for语句中的';'

    def do_check(self):
        if not self._process_file_to_lines():
            return self.output_buff_list

        if not self._process_twslint_mark():
            return self.output_buff_list

        # 常规检查, 与注释, 操作符无冲突
        self._check_filename_format() # 检查文件命名规范
        self._check_file_end_of_newline() # 检查文件最后一行应为空行
        self._check_line_length() # 检查每一行的长度(包含空格)
        self._check_line_end_with_blank() # 检查行尾是否有多余空白
        self._check_file_with_illegal_tab() # 检查文件中是否有tab符号
        self._check_file_language() # 文件中不应包含中文字符
        self._check_include_rules_in_header_file() # 头文件中不能有#include
        self._check_header_file_protect_by_marco() # 头文件应使用#ifdef _FILE_NAME_H_包含
        self._check_file_illegal_extern() # .c文件中不应使用extern

        # 注释检查会将注释替换成空白
        # 部分规范检查需要在此之前完成, 如空行检查, 行尾空白等
        # 部分规范检查需要在此后完成, 如construct分析, 运算符检查等.
        self._check_single_line_comments_and_replace_by_blank() # 检查"//"注释规范 must
        self._check_multi_line_comments_and_replace_by_blank() # 检查"/**/"注释规范 must

        # 常规检查, 与注释, 操作符无冲突, 但需要替代成空白或特殊字符串的
        # 由于这些操作符后, 可能存在注释, 因此将此项常规检查放在注释检查之后
        self._check_unsafe_memory_opration_funciton()
        self._check_hash_if_and_replace_by_blank() # 检查 #if等宏是否顶行书写
        self._check_hash_define_and_replace_by_blank() # 检查 #define等宏是否顶行书写
        self._check_include_format() # 检查#include格式

        # 此处会将字符和字符串, 替换为特定字符_STRING
        # 由于字符串中含有运算符, 因此所有特殊字符, 因此运算符检查需要在此之后进行
        self._findout_string_and_replace_by_blank()

        # 此函数会找到所有的enum/function/struct/union等原始定义, 并将lines中对应位置替换为空白, 并保存constructs信息到对应列表.
        # 由于很多运算符在不同结构中的使用方法不一样, 因此运算符检查需要使用此处生成的constructs list来检查.
        self._findout_all_multi_line_block()

        # 所有的复杂结构, 已经被拿到单独的list中检查, 剩下的主要是变量定义, 声明等信息
        # GuardCheckForRestOfTheLines(filename, file_extention, lines)
        self._check_struct_rules()
        self._check_enum_rules()
        self._check_union_rules()
        self._check_fuction_rules()
        # GuardCheckForHashDefineRule()

        return self.output_buff_list

def do_check_main(twslint_configfile,filepaths):
    logger.debug(f"twslint_configfile: {twslint_configfile}")
    configs = _parse_twslint_config(twslint_configfile)

    if not filepaths:
        _PrintUsage('No file specified')
    for filepath in filepaths:
        twslint = TwsLint(configs, filepath)
        errors = twslint.do_check()
        for err in errors:
            print(err)
    pass


if __name__ == "__main__":
    # logger config begin
    logging_config_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "./tws_lint_logging.ini")
    logging_config_logger = "root"
    log_conf_fd = open(logging_config_filepath, encoding="utf8")
    logging.config.fileConfig(log_conf_fd)
    logger = logging.getLogger(logging_config_logger)
    log_conf_fd.close()
    # logger config end

    configfile = sys.argv[1]
    filenames = sys.argv[2:]

    do_check_main(configfile, filenames)
    pass

